package org.rendao.dao;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;
import org.rendao.constant.ConstantDefinition;
import org.rendao.utils.ReflectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

@Transactional
public class GenericHibernateDao<T> implements
		IGenericDao<T> {
	private Class<T> clazz;

	@Autowired
	private SessionFactory sessionFactory;

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	protected Session getCurrentSession() {
		return sessionFactory.getCurrentSession();
	}

	@Override
	public void setClazz(Class<T> clazzToSet) {
		this.clazz = clazzToSet;
	}

	@SuppressWarnings("unchecked")
	@Override
	public T getById(String entityId) {
		return (T) getCurrentSession().get(clazz, entityId);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> getAll() {
		return getCurrentSession().createQuery("from " + clazz.getName())
				.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> getAllAvailable() {
		Criteria c = getCurrentSession().createCriteria(clazz);
		if(ReflectionUtils.hasProperty(clazz, "isDeleted")) {
			Criterion criterion = Restrictions.eq("isDeleted", ConstantDefinition.IS_DELETED_FALSE);
			c.add(criterion);
		}
		return c.list();
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public T save(T entity) {
		String id = (String)getCurrentSession().save(entity);
		return (T)getCurrentSession().get(clazz, id);
	}

	@SuppressWarnings("unchecked")
	@Override
	public T update(T entity) {
		return (T)getCurrentSession().merge(entity);
	}

	@Override
	public void delete(T entity) {
		getCurrentSession().delete(entity);
	}

	@Override
	public void deleteById(String entityId) {
		T entity = getById(entityId);
		delete(entity);
	}

	@Override
	public int softDelete(String entityId) {
		if(ReflectionUtils.hasProperty(clazz, "isDeleted")) {
			String hql = "UPDATE " + clazz.getName() + " set isDeleted = :isDeleted "  + 
		             "WHERE id = :id";
			Query query = getCurrentSession().createQuery(hql);
			query.setParameter("id", entityId);
			query.setParameter("isDeleted", ConstantDefinition.IS_DELETED_TRUE);
			int result = query.executeUpdate();
			return result;
		}
		return 0;
	}
}
